#协程： 
# 1. 协程是单线程下的并发，又称微线程，纤程。英文名Coroutine。
# 2. 一句话说明什么是协程：协程是一种用户态的轻量级线程，即协程是由用户程序自己控制调度的。 
# 3. 需要强调的是：
#     - 协程的调度完全由用户控制。
#     - 线程是操作系统控制调度。
#     - 协程拥有自己的寄存器上下文和栈。
#     - 协程调度切换时，将寄存器上下文和栈保存到其他地方，在切回来的时候，恢复先前保存的寄存器上下文和栈。
#     - 因此：
#         - 协程的切换效率比线程高很多。
#         - 因为子程序切换不是线程切换，而是由程序自身控制，因此，没有线程切换的开销，和多线程比，线程数量越多，协程的性能优势就越明显。
#         - 第二点不是绝对的，比如磁盘IO的切换。
#         - 但是，在协程中大部分时间都在CPU上，因此，协程的性能比线程高很多。
# 4. 对比操作系统控制线程的切换，用户在单线程内控制协程的切换。
# 5. 优点如下：
#     - 协程的切换开销更小，属于程序级别的切换，操作系统完全感知不到，因而更加轻量级。
#     - 单线程内就可以实现并发的效果，最大限度地利用CPU。
# 6. 缺点如下：
#     - 协程的本质是个单线程下，无法利用多核，可以是一个程序开启多个进程，每个进程内开启多个线程，每个线程内开启协程。
#     - 协程指的是单个线程，因而一旦协程出现阻塞，将会阻塞整个线程。
# 7. 对比多线程的优点，协程的最大优点就是协程极高的执行效率。
#     - 因为子程序切换不是线程切换，而是由程序自身控制，因此，没有线程切换的开销，和多线程比，线程数量越多，协程的性能优势就越明显。
# 8. 第二大优势就是不需要多线程的锁机制，因为只有一个线程，也不存在同时写变量冲突，在协程中控制共享资源不加锁，只需要判断状态就好了，所以执行效率比多线程高很多。
# 9. 因为协程是一个线程执行，那怎么利用多核CPU呢？
#     - 最简单的方法是多进程+协程，既充分利用多核，又充分发挥协程的高效率，可获得极高的性能。
# 10. Python对协程的支持是通过generator实现的。
#     - 在generator中，我们不但可以通过for循环来迭代，还可以不断调用next()函数获取由yield语句返回的下一个值。
#     - 但是Python的yield不但可以返回一个值，它还可以接收调用者发出的参数。
# 11. 来看例子：
#     - 传统的生产者-消费者模型是一个线程写消息，一个线程取消息，通过锁机制控制队列和等待，但一不小心就可能死锁。
#     - 如果改用协程，生产者生产消息后，直接通过yield跳转到消费者开始执行，待消费者执行完毕后，切换回生产者继续生产，效率极高：
# Example of producer-consumer model using coroutines

def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'

def producer(c):
    c.send(None)
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()

if __name__ == '__main__':
    c = consumer()
    producer(c)
